package thread;

import java.util.PriorityQueue;

/**
 * 定时器的构成:
 * 一个带优先级的阻塞队列
 * 队列中的每个元素是一个 Task 对象.
 * Task 中带有一个时间属性, 队首元素就是即将
 * 同时有一个 worker 线程一直扫描队首元素, 看队首元素是否需要执行
 */
class MyTimertask implements Comparable<MyTimertask>{
    //在什么时间点上来执行任务
    //约定time这个ms级别的时间戳
    private long time;

    //实际要执行的代码
    private Runnable runnable;

    public long getTime(){
        return time;
    }

    //delay 希望是个相对时间
    public MyTimertask(Runnable runnable,long delay){
        this.runnable = runnable;
        //System.currentTimeMillis()表示当前时刻  + delay 相对时间 =真正要执行任务的绝对时间
        this.time = System.currentTimeMillis() + delay;
    }

    public void run(){
        runnable.run();

    }
    @Override
    public int compareTo(MyTimertask o) {
        return (int) (this.time-o.time);
    }
}
//通过这个类表示一个定时器
class MyTimer{
    //负责扫描任务队列，执行任务的进程
    private Thread t = null;
    //任务队列
    private PriorityQueue<MyTimertask>queue =new PriorityQueue();

    public void schedule(Runnable runnable,long delay){
        synchronized(locker){
            MyTimertask task =new MyTimertask(runnable,delay);
            queue.offer(task);
            //添加成功新的元素后唤醒扫描线程的wait
            locker.notify();
        }
    }
    public void cancel(){
        Thread.interrupted();
    }
    private Object locker =new Object();
    //创建一个构造方法
    public MyTimer(){
        t = new Thread(() -> {
            while(!Thread.currentThread().isInterrupted()){
                //队列为空则等待唤醒
                try {
                    synchronized(locker){
                        while(queue.isEmpty()){
                            locker.wait();
                        }
                        //队列不为空则取出队首元素
                        MyTimertask task = queue.peek();
                        //获取当前时间
                        long curtime = System.currentTimeMillis();
                        //
                        if(curtime >= task.getTime()){
                            //当前时间已经达到任务时间了
                            queue.poll();
                            task.run();
                        }else{
                            //时间没到 需要等待当前时刻减去相对时刻的时间
                            //这里面，没有用sleep的原因是sleep的等待时间是固定的，
                            // 会错过新的任务，无法释放锁 要是中途有任务也无法唤醒需要等到sleep休眠时间到
                            //Thread.sleep(task.time()-SYstem.currentTimeMillis());
                            locker.wait(task.getTime()-System.currentTimeMillis());
                        }
                    }
                } catch (InterruptedException e) {
                }
            }

        });
        t.start();
    }

}
public class ThreadDemo12 {
    public static void main(String[] args) {
        MyTimer myTimer = new MyTimer();
        myTimer.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("hello 3000");
            }
        },3000);

        System.out.println("hello main");
        myTimer.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("hello 2000");
            }
        },2000);

        myTimer.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("hello 1000");
            }
        },1000);
    }
}
